package top.healthylife.gateway.feignapi.utils;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import lombok.SneakyThrows;
import top.healthylife.basics.utils.exception.BusinessException;
import top.healthylife.basics.utils.utils.R;
import top.healthylife.basics.utils.utils.SpringContextUtil;
import top.healthylife.gateway.dto.request.req.ApiReqDto;
import top.healthylife.gateway.dto.request.result.ApiResultDto;
import top.healthylife.gateway.feignapi.InterfaceApi;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author : maoxiaomeng
 */
public class ApiInvokeHelper {

    static Map<String, Class<?>> mapToBean = new HashMap<>(2);

    /**
     * 接口调用工具类
     * <p>当前版本缓存规则: 同一租户下 同一账号访问同一个接口,存在指定时间内入参且该次调用没有出现异常的记录,则视为命中有效缓存,如果没有符合条件的记录,将发起接口调用
     * <li> periodValidity<=0 :永不走缓存;
     * <li> periodValidity=0 :必定走缓存;
     * <li> periodValidity>0 :指定时间内走缓存;
     * <pre>如:periodValidity =5,则5秒内如果存在相同参数且调用没有异常的记录,则走缓存,如果没有符合条件的记录,将发起接口调用
     * @param shortName      三方数据源简称
     * @param apiName        接口名
     * @param data           参数
     * @param secret         系统生成的秘钥
     * @param periodValidity 缓存时间
     * @param <T>            入参
     * @return M extends ApiResultDto 出参
     */
    @SneakyThrows
    @SuppressWarnings("unchecked")
    public static <T extends ApiReqDto, M extends ApiResultDto> M results(String shortName, String apiName, T data, String secret, Long periodValidity) {
        InterfaceApi bean = SpringContextUtil.getBean(InterfaceApi.class);
        R<?> r = bean.results(shortName, apiName, BeanUtil.beanToMap(data), secret, periodValidity);
        Map<String, Object> map = (LinkedHashMap<String, Object>) r.getData();
        if (r.getCode() != 0) {
            throw new BusinessException(r.getMsg());
        }
        String cls1 = String.valueOf(map.get("cls"));
        Class<?> aClass;
        if (mapToBean.containsKey(cls1)) {
            aClass = mapToBean.get(cls1);
        } else {
            aClass = Class.forName(cls1);
            mapToBean.put(cls1, aClass);
        }
        return (M) BeanUtil.toBean(map, aClass, CopyOptions.create().setIgnoreCase(true));
    }


    /**
     * 调用此方法会使用各个数据源接口的默认缓存时间
     *
     * @param shortName 三方数据源简称
     * @param apiName   接口名
     * @param data      参数
     * @param secret    系统生成的秘钥
     * @param <T>       入参
     * @return M extends ApiResultDto 出参
     */
    @SneakyThrows
    public static <T extends ApiReqDto, M extends ApiResultDto> M results(String shortName, String apiName, T data, String secret) {
        return results(shortName, apiName, data, secret, null);
    }
}
